from pulp import LpMaximize, LpProblem, LpVariable
import itertools
from jinja2 import Environment, FileSystemLoader, select_autoescape

# 参数设定
T = 30  # 时间窗口总数
R = 75  # 直播间总数
M = 7   # 化妆师数量
COVER_RATE = 0.6

# 创建问题
prob = LpProblem("Live_Stream_Scheduling", LpMaximize)

# 决策变量
x = [[LpVariable(f"x_{t}_{r}", cat='Binary') for r in range(R)] for t in range(T)]
y = [[LpVariable(f"y_{t}_{r}", cat='Binary') for r in range(R)] for t in range(T)]
z = [[LpVariable(f"z_{t}_{r}", cat='Binary') for r in range(R)] for t in range(T)]

# 目标函数
N = sum([x[t][r] for t in range(2, 30) for r in range(R)])
prob += 4000 * N

# 约束条件
# 主播相关约束
for r in range(R):
    for t in range(2, 30):
        prob += sum([x[i][r] for i in range(max(0, t - 12), t + 1)]) <= 1
    for t in itertools.chain(range(0, 2), range(30, T)):
        prob += x[t][r] == 0

# 化妆师相关约束
for r in range(R):
    for t in itertools.chain(range(0, 10), range(12, 20)):
        prob += y[t][r] <= 1 - sum([x[i][r] for i in range(max(0, t - 2), t + 1)])
    for t in itertools.chain(range(0, 10), range(12, 20)):
        prob += sum([y[t][r] for r in range(R)]) <= M
    for t in set(range(T)) - set(itertools.chain(range(0, 10), range(12, 20))):
        prob += y[t][r] == 0

# 带妆主播相关约束
for r in range(R):
    for t in range(2, 30):
        prob += z[t][r] <= sum([y[tm][r] for tm in range(max(0, t - 11), t + 1)])
        prob += z[t][r] <= x[t][r]
prob += sum([z[t][r] for t in range(2, 30) for r in range(R)]) >= COVER_RATE * sum([x[t][r] for t in range(2, 30) for r in range(R)])

# 两次化妆之间必须至少有一次带妆直播
for r in range(R):
    for t1 in range(0, 20):
        for t2 in range(t1 + 1, 20):
            prob += y[t1][r] + y[t2][r] <= 1 + sum([z[tl][r] for tl in range(t1, t2)])

# 求解问题
prob.solve()

# 计算统计数据
total_streams = sum([x[t][r].value() for t in range(2, 30) for r in range(R)])
streams_with_makeup = sum([z[t][r].value() for t in range(2, 30) for r in range(R)])
makeup_rate = streams_with_makeup / total_streams if total_streams > 0 else 0

# 计算月净利润
monthly_profit = 4000 * total_streams - 9000 * M

# 时间映射
time_mapping = {
    0: "7:00", 1: "7:30", 2: "8:00", 3: "8:30", 4: "9:00",
    5: "9:30", 6: "10:00", 7: "10:30", 8: "11:00", 9: "11:30",
    10: "12:00", 11: "12:30", 12: "13:00", 13: "13:30", 14: "14:00",
    15: "14:30", 16: "15:00", 17: "15:30", 18: "16:00", 19: "16:30",
    20: "17:00", 21: "17:30", 22: "18:00", 23: "18:30", 24: "19:00",
    25: "19:30", 26: "20:00", 27: "20:30", 28: "21:00", 29: "21:30"
}

# 生成化妆师排班表数据
makeup_artists = [f"化妆师{'abcdefg'[i]}" for i in range(M)]
makeup_artist_schedule = {}

for t in range(T):
    # 获取当前时间所有正在进行的化妆工作，并按直播间排序
    active_makeup_rooms = sorted([r for r in range(R) if y[t][r].value() == 1])
    
    # 分配给化妆师
    assignments = {}
    for i, room in enumerate(active_makeup_rooms):
        if i < M:  # 确保不超过化妆师数量
            assignments[makeup_artists[i]] = room + 1  # 直播间从1开始编号
    
    makeup_artist_schedule[time_mapping.get(t, f"未知时间({t})")] = assignments

# 生成直播间使用情况数据
room_schedule = {}
for t in range(T):
    time_slot = time_mapping.get(t, f"未知时间({t})")
    room_schedule[time_slot] = []
    for r in range(R):
        room_num = r + 1  # 直播间从1开始编号
        status = ""
        makeup_class = ""
        
        if x[t][r].value() == 1:
            if z[t][r].value() == 1:
                status = "开始带妆直播"
                makeup_class = "with-makeup"
            else:
                status = "开始直播"
                makeup_class = "without-makeup"
        elif y[t][r].value() == 1:
            status = "开始化妆"
            makeup_class = "makeup"
        
        room_schedule[time_slot].append({
            "room": room_num,
            "status": status,
            "class": makeup_class
        })

# 创建Jinja2环境并注册过滤器
env = Environment(
    autoescape=select_autoescape(['html', 'xml']),
    trim_blocks=True,
    lstrip_blocks=True
)

# 注册自定义过滤器
def format_percentage(value):
    return f"{value * 100:.2f}%"

env.filters['format_percentage'] = format_percentage

# HTML模板
html_template = env.from_string('''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>直播间排班表</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .with-makeup {
                background-color: rgba(16, 185, 129, 0.2);
            }
            .without-makeup {
                background-color: rgba(249, 115, 22, 0.2);
            }
            .makeup {
                background-color: rgba(59, 130, 246, 0.2);
            }
            .table-header {
                background-color: #f8fafc;
            }
            .table-cell {
                border: 1px solid #e2e8f0;
            }
        }
    </style>
</head>
<body class="bg-gray-50 font-sans">
    <div class="container mx-auto px-4 py-8">
        <h1 class="text-3xl font-bold text-gray-800 mb-6">直播间排班系统</h1>
        
        <div class="bg-white rounded-lg shadow-lg p-6 mb-8">
            <h2 class="text-xl font-bold text-gray-700 mb-4">统计信息</h2>
            <div class="grid grid-cols-1 md:grid-cols-4 gap-4">
                <div class="bg-blue-50 rounded-lg p-4 border-l-4 border-blue-500">
                    <p class="text-sm text-blue-700 font-medium">总直播场次</p>
                    <p class="text-2xl font-bold text-gray-800">{{ total_streams }}</p>
                </div>
                <div class="bg-green-50 rounded-lg p-4 border-l-4 border-green-500">
                    <p class="text-sm text-green-700 font-medium">带妆直播场次</p>
                    <p class="text-2xl font-bold text-gray-800">{{ streams_with_makeup }}</p>
                </div>
                <div class="bg-purple-50 rounded-lg p-4 border-l-4 border-purple-500">
                    <p class="text-sm text-purple-700 font-medium">化妆率</p>
                    <p class="text-2xl font-bold text-gray-800">{{ makeup_rate|format_percentage }}</p>
                </div>
                <div class="bg-yellow-50 rounded-lg p-4 border-l-4 border-yellow-500">
                    <p class="text-sm text-yellow-700 font-medium">月净利润</p>
                    <p class="text-2xl font-bold text-gray-800">{{ monthly_profit }}</p>
                </div>
            </div>
        </div>
        
        <div class="bg-white rounded-lg shadow-lg p-6 mb-8">
            <h2 class="text-xl font-bold text-gray-700 mb-4">
                <i class="fa fa-user-circle mr-2"></i>化妆师排班表
            </h2>
            <div class="overflow-x-auto">
                <table class="min-w-full divide-y divide-gray-200">
                    <thead>
                        <tr class="bg-gray-50">
                            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">时间</th>
                            {% for artist in makeup_artists %}
                            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                {{ artist }}
                            </th>
                            {% endfor %}
                        </tr>
                    </thead>
                    <tbody class="bg-white divide-y divide-gray-200">
                        {% for time, assignments in makeup_artist_schedule.items() %}
                        <tr>
                            <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
                                {{ time }}
                            </td>
                            {% for artist in makeup_artists %}
                            <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
                                {% if artist in assignments %}
                                在直播间{{ assignments[artist] }}工作
                                {% else %}
                                休息
                                {% endif %}
                            </td>
                            {% endfor %}
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
        
        <div class="bg-white rounded-lg shadow-lg p-6 mb-8">
            <h2 class="text-xl font-bold text-gray-700 mb-4">
                <i class="fa fa-video-camera mr-2"></i>直播间使用情况
            </h2>
            <div class="mb-4">
                <div class="flex items-center space-x-4">
                    <div class="flex items-center">
                        <div class="w-4 h-4 rounded-full bg-green-300 mr-2"></div>
                        <span class="text-sm text-gray-600">开始带妆直播</span>
                    </div>
                    <div class="flex items-center">
                        <div class="w-4 h-4 rounded-full bg-orange-300 mr-2"></div>
                        <span class="text-sm text-gray-600">开始普通直播</span>
                    </div>
                    <div class="flex items-center">
                        <div class="w-4 h-4 rounded-full bg-blue-300 mr-2"></div>
                        <span class="text-sm text-gray-600">开始化妆</span>
                    </div>
                </div>
            </div>
            <div class="overflow-x-auto">
                <table class="min-w-full divide-y divide-gray-200">
                    <thead>
                        <tr class="bg-gray-50">
                            <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">时间</th>
                            {% for room_num in range(1, R+1) %}
                            <th class="px-3 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
                                {{ room_num }}
                            </th>
                            {% endfor %}
                        </tr>
                    </thead>
                    <tbody class="bg-white divide-y divide-gray-200">
                        {% for time, rooms in room_schedule.items() %}
                        <tr>
                            <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
                                {{ time }}
                            </td>
                            {% for room in rooms %}
                            <td class="px-3 py-2 text-center text-xs {% if room.class %} {{ room.class }} {% endif %}">
                                {{ room.status }}
                            </td>
                            {% endfor %}
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</body>
</html>
''')

# 渲染并保存HTML
with open('scheduling_report_experiment1_part1.html', 'w', encoding='utf-8') as f:
    f.write(html_template.render(
        makeup_artists=makeup_artists,
        makeup_artist_schedule=makeup_artist_schedule,
        room_schedule=room_schedule,
        total_streams=total_streams,
        streams_with_makeup=streams_with_makeup,
        makeup_rate=makeup_rate,
        monthly_profit=monthly_profit,
        R=R
    ))

print("排班表已输出到 scheduling_report_experiment1_part1.html 文件中")
print(f"化妆率: {makeup_rate:.2%}")
print(f"月净利润: {monthly_profit}")